﻿using BusyReports.ReportingService;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Linq;

namespace BusyReports
{
    public class BusyReportsViewModel : BaseViewModel
    {
        private ReportingService2010 theReportService;
        private ObservableCollection<BusySubscription> theSubscriptions;
        private ObservableCollection<BusySubscription> theFilteredSubscriptions;
        private BusySubscription theCurrentSubscription;

        private ObservableCollection<BusySubscriptionsParameter> theParameters;
        private string theFilter = "Filter..";
        private Boolean theIsEdit = false;
        private Boolean theIsFile;
        private Boolean theIsMail;

        List<BackgroundWorker> theBackgroundWorkers = new List<BackgroundWorker>();
        int theBackgroundWorkersCount = 0;

        public BusyReportsViewModel()
        {
            theContext = new BusyReportsEntities();
            theReportService = new ReportingService2010();
            theReportService.UseDefaultCredentials = true;
        }
        private BusyReportsEntities theContext;

        private ObservableCollection<BusySubscription> AllBusySubscription
        {
            get
            {
                theContext = new BusyReportsEntities();
                theSubscriptions = new ObservableCollection<BusySubscription>();

                try
                {

                    var q = theContext.BusySubscriptions;
                    //  .Include("BusySubscription.BusySubscriptionsParameters");
                    //.Include("BusyFileSubscription")
                    //.Include("BusyMailSubscription")

                    foreach (BusySubscription b in q)
                    {

                        theSubscriptions.Add(b);
                    }

                }
                catch (Exception e)
                {
                    //
                }
                return theSubscriptions;

            }
        }
        public Boolean IsEdit
        {
            get { return theIsEdit; }
            set
            {
                theIsEdit = value;
                RaisePropertyChanged("IsEdit");
                RaisePropertyChanged("IsReadOnly");
            }
        }
        public Boolean IsReadOnly
        {
            get { return !theIsEdit; }

        }
        public string ConnectionInfo
        {
            get
            {
                return "Database: " + theContext.Database.Connection.DataSource + "." + theContext.Database.Connection.Database + " ReportServer : " + theReportService.Url;
            }
            set { }
        }

        public Boolean IsFileSubscription
        {
            get { return theIsFile; }
            set
            {
                if (theIsFile != value)
                {
                    theIsFile = value;
                    RaisePropertyChanged("IsFileSubscription");

                }
            }
        }
        public Boolean IsMailSubscription
        {
            get { return theIsMail; }
            set
            {
                if (theIsMail != value)
                {
                    theIsMail = value;
                    RaisePropertyChanged("IsMailSubscription");
                }
            }
        }

        public BusySubscription BusySubscription
        {
            get { return theCurrentSubscription; }
            set
            {
                theCurrentSubscription = value;
                if (theCurrentSubscription != null)
                {
                    if (theCurrentSubscription.Type == "FILE")
                    {
                        IsFileSubscription = true;
                        IsMailSubscription = false;
                        //BusyFileSubscription = theCurrentSubscription.BusyFileSubscription;
                    }
                    if (theCurrentSubscription.Type == "MAIL")
                    {
                        IsFileSubscription = false;
                        IsMailSubscription = true;
                        // BusyMailSubscription = theCurrentSubscription.BusyMailSubscription;
                    }

                }

                RaisePropertyChanged("BusySubscription");

                RaisePropertyChanged("Parameters");
            }
        }

        public string Filter
        {
            get { return theFilter; }
            set
            {
                theFilter = value;
                RaisePropertyChanged("Filter");
                RaisePropertyChanged("Subscriptions");
            }
        }

        public ObservableCollection<BusySubscription> Subscriptions
        {
            get
            {
                theFilteredSubscriptions = new ObservableCollection<BusySubscription>();
                var q = from a in AllBusySubscription
                        where a.ReportPath.ToUpper().Contains(this.Filter.ToUpper())
                        || this.Filter.ToUpper() == "FILTER.."
                        select a;

                foreach (BusySubscription b in q)
                {
                    theFilteredSubscriptions.Add(b);
                }


                return theFilteredSubscriptions;
            }
            set { theFilteredSubscriptions = value; }
        }

        public ObservableCollection<BusySubscriptionsParameter> Parameters
        {
            get
            {
                if (theCurrentSubscription == null) return null;

                theParameters = new ObservableCollection<BusySubscriptionsParameter>();

                foreach (BusySubscriptionsParameter b in theCurrentSubscription.BusySubscriptionsParameters)
                {
                    theParameters.Add(b);
                }

                return theParameters;
            }
            set { theParameters = value; }
        }


        public void newMailSubscription(string aPath)
        {

            BusySubscription d = new BusySubscription()
            {
                ReportPath = aPath,
                LastStatus = "New",
                Type = "MAIL"
            };

            d.BusyMailSubscription = new BusyMailSubscription()
            {
                To = "",
                Cc = "",
                Bcc = "",
                AttachementName = aPath.Substring(aPath.LastIndexOf("/") + 1, aPath.Length - aPath.LastIndexOf("/") - 1),
                Subject = aPath.Substring(aPath.LastIndexOf("/") + 1, aPath.Length - aPath.LastIndexOf("/") - 1),
                AttachementFormat = "EXCEL",
                ReportAsAttachement = false,
                Comment = "",
                IncludeLinkToReport = false,
                ReportInMailBody = true,
                From = Properties.Settings.Default.DefaultFromEmail,
                Priority = "Normal"
            };

            theContext.BusySubscriptions.Add(d);
            theContext.SaveChanges();
            reloadParameters(d);
            RaisePropertyChanged("Subscriptions");
        }


        public void deleteSubscription(BusyReports.BusySubscription aBusySubscription)
        {

            var q = aBusySubscription.BusySubscriptionsParameters.ToList();

            foreach (BusySubscriptionsParameter p in q)
            {
                theContext.BusySubscriptionsParameters.Remove(p);
            }

            theContext.Entry(aBusySubscription).Reference(u => u.BusyFileSubscription).Load();
            theContext.Entry(aBusySubscription).Reference(u => u.BusyFileSubscription).Load();

            if (aBusySubscription.BusyFileSubscription != null) theContext.BusyFileSubscriptions.Remove(aBusySubscription.BusyFileSubscription);
            if (aBusySubscription.BusyMailSubscription != null) theContext.BusyMailSubscriptions.Remove(aBusySubscription.BusyMailSubscription);
            theContext.BusySubscriptions.Remove(aBusySubscription);
            save();

        }

        public void newFileSubscription(string aPath)
        {
            BusySubscription d = new BusySubscription()
            {
                ReportPath = aPath,
                LastStatus = "New",
                Type = "FILE",
            };

            d.BusyFileSubscription = new BusyFileSubscription()
            {
                Path = "c:\\temp\\" + aPath.Substring(aPath.LastIndexOf("/") + 1, aPath.Length - aPath.LastIndexOf("/") - 1) + ".xls",
                Format = "EXCEL"
            };

            theContext.BusySubscriptions.Add(d);

            theContext.SaveChanges();
            reloadParameters(d);
            RaisePropertyChanged("Subscriptions");

        }

        public void save()
        {
            // theContext.ChangeTracker.HasChanges();
            try
            {
                theContext.SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex)
            {
                var myContext = ((IObjectContextAdapter)theContext).ObjectContext;
                myContext.Refresh(RefreshMode.ClientWins, ex.Entries.Select(e => e.Entity));
            }
        }
        public void reloadParameters()
        {
            reloadParameters(theCurrentSubscription);
        }
        public void reloadParameters(BusySubscription aBusySubscription)
        {
                        foreach (BusySubscriptionsParameter b in theContext.BusySubscriptionsParameters.Where(a => a.BusyReportId == aBusySubscription.id))
            { aBusySubscription.BusySubscriptionsParameters.Remove(b); }

            try
            {
                ItemParameter[] myParameters = theReportService.GetItemParameters(
                aBusySubscription.ReportPath, null, false, null, null);
                foreach (ItemParameter p in myParameters)
                {
                    BusySubscriptionsParameter mPa = new BusySubscriptionsParameter();
                    mPa.BusyReportId = aBusySubscription.id;
                    mPa.ParameterName = p.Name;
                    mPa.ParameterValue = "";
                    if (p.DefaultValues != null | p.DefaultValuesQueryBasedSpecified == true | p.PromptUser == false)
                    {
                        mPa.ParameterUseDefault = true;
                    }

                    aBusySubscription.BusySubscriptionsParameters.Add(mPa);

                }
            }
            catch (Exception ex )
            {
                throw new Exception("Report not Found in Reporting Services" + ex.Message);
            }


            theContext.SaveChanges();
            RaisePropertyChanged("Parameters");
        }

        public bool checkChanges()
        {
            if (theContext.ChangeTracker.HasChanges())
            {
                return true;
            }
            return false;
        }
        public bool checkRunning()
        {
            if (theBackgroundWorkersCount > 0)
            {
                return true;
            }
            return false;
        
        }

        public void run(List<BusySubscription> aBusySubscriptions)
        {
            foreach (BusySubscription myBusySubscription in aBusySubscriptions.OrderBy(a => a.id))
            {
                myBusySubscription.LastRun = null;
                myBusySubscription.LastRunDurationSeconds = null;
                myBusySubscription.LastStatus = "Queued";

            }
            save();
            foreach (BusySubscription myBusySubscription in aBusySubscriptions.OrderBy(a => a.id))
            {
                BackgroundWorker myBackgroundWorker = new BackgroundWorker();
                myBackgroundWorker.DoWork += new DoWorkEventHandler(bw_DoWork);
                myBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
                myBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
                myBackgroundWorker.WorkerReportsProgress = true;
                theBackgroundWorkers.Add(myBackgroundWorker);
                myBackgroundWorker.RunWorkerAsync(myBusySubscription);
            }
        }


        public void testRun(List<BusySubscription> aBusySubscriptions)
        {
            foreach (BusySubscription myBusySubscription in aBusySubscriptions.OrderBy(a => a.id))
            {
                myBusySubscription.LastRun = null;
                myBusySubscription.LastRunDurationSeconds = null;
                myBusySubscription.LastStatus = "Queued";

            }
            save();
            foreach (BusySubscription myBusySubscription in aBusySubscriptions.OrderBy(a => a.id))
            {

                BackgroundWorker myBackgroundWorker = new BackgroundWorker();
                myBackgroundWorker.DoWork += new DoWorkEventHandler(bw_DoWorkTest); // different handler for test runs
                myBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
                myBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
                myBackgroundWorker.WorkerReportsProgress = true;
                theBackgroundWorkers.Add(myBackgroundWorker);
                myBackgroundWorker.RunWorkerAsync(myBusySubscription);
            }
        }

        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            waitIfTooManyThreads();
            theBackgroundWorkersCount += 1;
            BackgroundWorker worker = sender as BackgroundWorker;
            BusySubscription myBusySubscription = (BusySubscription)e.Argument;
            BusyRunner r = new BusyRunner(myBusySubscription, worker);
            r.run();

        }

        private void waitIfTooManyThreads()
        {
            int myMaxThreads = Math.Max(Convert.ToInt32(Properties.Settings.Default.MaxThreads) - 1, 0);
            while (theBackgroundWorkersCount > myMaxThreads)
            {
                System.Threading.Thread.Sleep(1000);
            }

        }
        public void waitForFinish()
        {

            while (theBackgroundWorkers.Count(a => a.IsBusy == true) > 0)
            {
                System.Threading.Thread.Sleep(1000);
            }
        }
        private void bw_DoWorkTest(object sender, DoWorkEventArgs e)
        {
            waitIfTooManyThreads();
            theBackgroundWorkersCount += 1;
            BackgroundWorker worker = sender as BackgroundWorker;
            BusySubscription myBusySubscription = (BusySubscription)e.Argument;
            BusyRunner r = new BusyRunner(myBusySubscription, worker);
            r.IsTestRun = true;
            r.run();

        }
        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            theBackgroundWorkersCount -= 1;
            RaisePropertyChanged("Subscriptions");
        }
        private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            RaisePropertyChanged("Subscriptions");
        }


        public void reloadContext()
        {
            RaisePropertyChanged("Subscriptions");
        }
    }
}
